/**
 * @file wa_editline.c
 *
 */

 /*********************
 *      INCLUDES
 *********************/
#include "wa_conf.h"
#if USE_WA_EDITLINE != 0
#include "wa_editline.h"

 /*********************
 *      DEFINES
 *********************/

 /**********************
 *      TYPEDEFS
 **********************/

 /**********************
 *  STATIC PROTOTYPES
 **********************/
static wa_obj_callback ancestor_callback;
static void wa_editline_callback(wa_sign* sign);

/**********************
 *  STATIC VARIABLES
 **********************/

 /**********************
 *      MACROS
 **********************/

 /**********************
 *   GLOBAL FUNCTIONS
 **********************/
 /**
 * editline module init
 */
void wa_editline_module_init(void)
{
}

/**
* create a editline
* @param par
* @return editline obj
*/
wa_obj* wa_editline_create(wa_obj* par)
{
	wa_obj* new_editline;
	wa_editline_ext* editline_ext;

	new_editline = wa_obj_create(par, NULL);
	if (new_editline == NULL)
	{
		return new_editline;
	}

	if (ancestor_callback == NULL)
	{
		ancestor_callback = wa_obj_get_callback(new_editline);
	}
	editline_ext = wa_obj_malloc_ext_attr(new_editline, sizeof(wa_editline_ext));
	if (editline_ext == NULL)
	{
		return NULL;
	}

	editline_ext->focus = -1;
	editline_ext->text = NULL;
	editline_ext->font = NULL;
	editline_ext->row_space = 0;
	editline_ext->col_space = 0;
	editline_ext->fore_color = WA_COLOR_FOREGROUND;
	editline_ext->back_color = WA_COLOR_BACKGROUND;
	editline_ext->align_mode = WA_EDITLINE_AL_LEFT | WA_EDITLINE_AL_TOP;

	wa_obj_set_callback(new_editline, wa_editline_callback);

	return new_editline;
}

/**
* editline set focus
* @param editline
* @param focus
*/
void wa_editlint_set_focus(wa_obj* editline, int32_t focus)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	if (focus > (wa_editline_get_focus_size(editline) - 1))
	{
		return;
	}
	ext->focus = focus;
	wa_obj_invalidate(editline);
}

/**
* editline get focus
* @param editline
* @return focus
*/
int32_t wa_editline_get_focus(wa_obj* editline)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	return ext->focus;
}

/**
* editline get focus letter offset
* @param editline
* @param offset
*/
int32_t wa_editline_get_focus_letter_offset(wa_obj* editline)
{
	wa_editline_ext* ext;
	uint8_t* str;
	int32_t focus_offset = 0;
	uint8_t hz = 0;
	uint32_t offset = 0;
	ext = wa_obj_get_ext_attr(editline);
	if (ext->focus < 0)
	{
		return -1;
	}
	str = (uint8_t*)ext->text;
	while (*str != '\0')
	{
		if (hz == 0)
		{
			if (*str > 0x80)
			{
				hz = 1;
			}
			else
			{
				if ((*str == '\r') || (*str == '\n'))
				{
					str++;
				}
				else
				{
					if (ext->focus == focus_offset)
					{
						return offset;
					}
					str++;
					focus_offset++;
					offset++;
				}
			}
		}
		else
		{
			hz = 0;
			if (ext->focus == focus_offset)
			{
				return offset;
			}
			str += 2;
			focus_offset++;
			offset += 2;
		}
	}
	return -1;
}

/**
* editline get max focus
* @param editline
* @param how many can be focus
*/
int32_t wa_editline_get_focus_size(wa_obj* editline)
{
	wa_editline_ext* ext;
	uint8_t* str;
	uint8_t hz = 0;
	int32_t max = 0;
	ext = wa_obj_get_ext_attr(editline);
	str = (uint8_t*)ext->text;
	while (*str != '\0')
	{
		if (hz == 0)
		{
			if (*str > 0x80)
			{
				hz = 1;
			}
			else
			{
				if ((*str == '\r') || (*str == '\n'))
				{
					str++;
				}
				else
				{
					str++;
					max++;
				}
			}
		}
		else
		{
			hz = 0;
			str += 2;
			max++;
		}
	}
	return max;
}

/**
* editline get focus letter
* @param editline
* @return letter
*/
uint32_t wa_editline_get_focus_letter(wa_obj* editline)
{
	wa_editline_ext* ext;
	uint8_t* str;
	int32_t focus_offset = 0;
	uint8_t hz = 0;
	ext = wa_obj_get_ext_attr(editline);
	if (ext->focus < 0)
	{
		return 0;
	}
	str = (uint8_t*)ext->text;
	while (*str != '\0')
	{
		if (hz == 0)
		{
			if (*str > 0x80)
			{
				hz = 1;
			}
			else
			{
				if ((*str == '\r') || (*str == '\n'))
				{
					str++;
				}
				else
				{
					if (ext->focus == focus_offset)
					{
						return (uint32_t)(*str);
					}
					str++;
					focus_offset++;
				}
			}
		}
		else
		{
			hz = 0;
			if (ext->focus == focus_offset)
			{
				uint32_t letter;
				letter = (((uint32_t)(*str)) << 8) + ((uint32_t)(*(str + 1)));
				return letter;
			}
			str += 2;
			focus_offset++;
		}
	}
	return 0;
}


/**
* editline set text
* @param editline
* @param text
*/
void wa_editline_set_text(wa_obj* editline, char* text)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	if (ext->text != NULL)
	{
		wa_free(ext->text);
	}
	if (text != NULL)
	{
		ext->text = wa_malloc(strlen((const char*)text) + 1);
		strcpy((char*)(ext->text), (char*)text);
	}
	else
	{
		ext->text = NULL;
	}
	wa_obj_invalidate(editline);
}

/**
* editline get text
* @param editline
* @param text dst array point
* @param size how many want to get
* @return how many get
*/
int32_t wa_editline_get_text(wa_obj* editline, char* text, uint32_t size)
{
	wa_editline_ext* ext;
	uint32_t len;
	ext = wa_obj_get_ext_attr(editline);
	if (ext->text == NULL)
	{
		return -1;
	}
	len = strlen((const char*)(ext->text)) + 1;
	if (size >= len)
	{
		strcpy((char*)text, (char*)(ext->text));
		return len;
	}
	else
	{
		memcpy(text, ext->text, size);
		return size;
	}
}

/**
* editline set row space
* @param editline
* @param row space
*/
void wa_editline_set_row_space(wa_obj* editline, uint8_t row_space)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	ext->row_space = row_space;
	wa_obj_invalidate(editline);
}

/**
* editline get row space
* @param editline
* @return row space
*/
uint8_t wa_editline_get_row_space(wa_obj* editline)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	return ext->row_space;
}

/**
* editline set col space
* @param editline
* @param col space
*/
void wa_editline_set_col_space(wa_obj* editline, uint8_t col_space)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	ext->col_space = col_space;
	wa_obj_invalidate(editline);
}

/**
* editline get col space
* @param editline
* @return col space
*/
uint8_t wa_editline_get_col_space(wa_obj* editline)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	return ext->col_space;
}

/**
* editline set font
* @param editline
* @param font
*/
void wa_editline_set_font(wa_obj* editline, wa_font* font)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	ext->font = font;
	wa_obj_invalidate(editline);
}

/**
* editline get font
* @param editline
* @return font
*/
wa_font* wa_editline_get_font(wa_obj* editline)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	return ext->font;
}

/**
* editline set fore color
* @param editline
* @param fore color
*/
void wa_editline_set_fore_color(wa_obj* editline, wa_gui_color color)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	ext->fore_color = color;
	wa_obj_invalidate(editline);
}

/**
* editline get fore color
* @param editline
* @return fore color
*/
wa_gui_color wa_editline_get_fore_color(wa_obj* editline)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	return ext->fore_color;
}

/**
* editline set back color
* @param editline
* @param back color
*/
void wa_editline_set_back_color(wa_obj* editline, wa_gui_color color)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	ext->back_color = color;
	wa_obj_invalidate(editline);
}

/**
* editline get back color
* @param editline
* @return back color
*/
wa_gui_color wa_editline_get_back_color(wa_obj* editline)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	return ext->back_color;
}

/**
* editline set align mode
* @param editline
* @param align mode
*/
void wa_editline_set_align_mode(wa_obj* editline, uint8_t align_mode)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	ext->align_mode = align_mode;
	wa_obj_invalidate(editline);
}

/**
* editline get align mode
* @param editline
* @return align mode
*/
uint8_t wa_editline_get_align_mode(wa_obj* editline)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(editline);
	return ext->align_mode;
}


/**********************
*   STATIC FUNCTIONS
**********************/

/**
* editline redraw functions
* @param obj
*/
static void _Paint(wa_obj* obj)
{
	int pw, ph;
	int str_w, str_h;
	int str_x = 0;
	int str_y = 0;
	wa_area str_area;
	uint8_t* str;
	int x0, y0;
	int x, y;
	int letter_w, letter_h;
	uint8_t hz = 0;
	wa_area conn;
	int32_t focus_offset = 0;
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(obj);

	if (ext->font == NULL)
	{
		return;
	}
	if(ext->text == NULL)
	{
		return;
	}
	pw = wa_obj_get_width(obj);
	ph = wa_obj_get_height(obj);

	wa_mask_fillrect(obj->rect.x1, obj->rect.y1,
					pw,
					ph,
					&(obj->redraw_rect),
					ext->back_color);

	wa_font_get_str_size(&str_w, &str_h, (uint8_t*)ext->text, ext->font, ext->row_space, ext->col_space);
	if ((ext->align_mode & 0x03) == WA_EDITLINE_AL_LEFT)
	{
		str_x = obj->rect.x1;
	}
	else if ((ext->align_mode & 0x03) == WA_EDITLINE_AL_RIGHT)
	{
		str_x = obj->rect.x2 - str_w;
	}
	else if ((ext->align_mode & 0x03) == WA_EDITLINE_AL_HCENTER)
	{
		str_x = obj->rect.x1 + ((int)pw - (int)str_w) / 2;
	}
	else
	{

	}

	if ((ext->align_mode & 0x0c) == WA_EDITLINE_AL_TOP)
	{
		str_y = obj->rect.y1;
	}
	else if ((ext->align_mode & 0x0c) == WA_EDITLINE_AL_BOTTOM)
	{
		str_y = obj->rect.y2 - str_h;
	}
	else if ((ext->align_mode & 0x0c) == WA_EDITLINE_AL_VCENTER)
	{
		str_y = obj->rect.y1 + ((int)ph - (int)str_h) / 2;
	}
	else
	{

	}

	str_area.x1 = str_x;
	str_area.y1 = str_y;
	str_area.x2 = str_x + str_w - 1;
	str_area.y2 = str_y + str_h - 1;

	if (wa_area_union(&conn, &str_area, &(obj->redraw_rect)) != wa_ok)
	{
		return;
	}

	x0 = str_area.x1;
	y0 = str_area.y1;
	x = x0;
	y = y0;
	letter_h = wa_font_get_height(ext->font);

	str = (uint8_t*)ext->text;
	while (*str != '\0')
	{
		if (hz == 0)
		{
			if (*str > 0x80)
			{
				hz = 1;
			}
			else
			{
				letter_w = wa_font_get_width(ext->font, (uint32_t)(*str));
				if ((*str == '\r') || (*str == '\n'))
				{
					y += letter_h;
					y += ext->row_space;
					x = x0;
					str++;
				}
				else
				{
					if ((ext->focus >= 0) && (ext->focus == focus_offset))
					{
						wa_mask_fillrect(x, y, letter_w, letter_h, &conn, ext->fore_color);
						wa_mask_dispchar(x, y, (uint32_t)*str, ext->font, &conn, ext->back_color);	
					}
					else
					{
						wa_mask_dispchar(x, y, (uint32_t)*str, ext->font, &conn, ext->fore_color);
					}
					x += letter_w;
					x += ext->col_space;
					str++;
					focus_offset++;
				}
			}
		}
		else
		{
			uint32_t letter;
			hz = 0;
			letter = (((uint32_t)(*str)) << 8) + ((uint32_t)(*(str + 1)));
			letter_w = wa_font_get_width(ext->font, letter);
			if ((ext->focus >= 0) && (ext->focus == focus_offset))
			{
				wa_mask_fillrect(x, y, letter_w, letter_h, &conn, ext->fore_color);
				wa_mask_dispchar(x, y, letter, ext->font, &conn, ext->back_color);
			}
			else
			{
				wa_mask_dispchar(x, y, letter, ext->font, &conn, ext->fore_color);
			}
			x += letter_w;
			x += ext->col_space;
			str += 2;
			focus_offset++;
		}
	}
}

/**
 * editline obj delete function
 * @param obj
 */
static void _Delete(wa_obj* obj)
{
	wa_editline_ext* ext;
	ext = wa_obj_get_ext_attr(obj);
	if (ext->text != NULL)
	{
		wa_free(ext->text);
	}
}

/**
 * editline obj callback function
 * @param sign
 */
static void wa_editline_callback(wa_sign* sign)
{
	int sign_id;
	wa_obj* obj;

	ancestor_callback(sign);
	sign_id = sign->sign_id;
	obj = sign->obj_dst;

	switch (sign_id)
	{
	case WA_SIGNAL_PAINT:
	{
		_Paint(obj);
		break;
	}
	case WA_SIGNAL_DELETE:
	{
		_Delete(obj);
		break;
	}
	default:
	{
		break;
	}
	}
}

#endif
